home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / Src / Ch12 / Hexes2.frm (.txt) < prev    next >
Encoding:
Visual Basic Form  |  1999-06-19  |  14.2 KB  |  468 lines

  1. VERSION 5.00
  2. Begin VB.Form frmHexes2 
  3.    Caption         =   "Hexes2"
  4.    ClientHeight    =   3150
  5.    ClientLeft      =   2550
  6.    ClientTop       =   1800
  7.    ClientWidth     =   3150
  8.    LinkTopic       =   "Form1"
  9.    PaletteMode     =   1  'UseZOrder
  10.    ScaleHeight     =   3150
  11.    ScaleWidth      =   3150
  12.    Begin VB.HScrollBar HScrollBar 
  13.       Height          =   255
  14.       Left            =   0
  15.       TabIndex        =   2
  16.       Top             =   2880
  17.       Width           =   2895
  18.    End
  19.    Begin VB.VScrollBar VScrollBar 
  20.       Height          =   2895
  21.       Left            =   2880
  22.       TabIndex        =   1
  23.       Top             =   0
  24.       Width           =   255
  25.    End
  26.    Begin VB.PictureBox picCanvas 
  27.       Height          =   2880
  28.       Left            =   0
  29.       ScaleHeight     =   2820
  30.       ScaleWidth      =   2820
  31.       TabIndex        =   0
  32.       Top             =   0
  33.       Width           =   2880
  34.    End
  35.    Begin VB.Menu mnuFile 
  36.       Caption         =   "&File"
  37.       Begin VB.Menu mnuFileExit 
  38.          Caption         =   "E&xit"
  39.       End
  40.    End
  41.    Begin VB.Menu mnuScale 
  42.       Caption         =   "&Scale"
  43.       Begin VB.Menu mnuScaleZoom 
  44.          Caption         =   "&Zoom"
  45.          Shortcut        =   ^Z
  46.       End
  47.       Begin VB.Menu mnuScaleMag 
  48.          Caption         =   "Full  Scale"
  49.          Index           =   1
  50.          Shortcut        =   ^F
  51.       End
  52.       Begin VB.Menu mnuScaleMag 
  53.          Caption         =   "Magnify 1/2"
  54.          Index           =   20
  55.          Shortcut        =   ^{F2}
  56.       End
  57.       Begin VB.Menu mnuScaleMag 
  58.          Caption         =   "Magnify 1/4"
  59.          Index           =   40
  60.          Shortcut        =   ^{F4}
  61.       End
  62.    End
  63. Attribute VB_Name = "frmHexes2"
  64. Attribute VB_GlobalNameSpace = False
  65. Attribute VB_Creatable = False
  66. Attribute VB_PredeclaredId = True
  67. Attribute VB_Exposed = False
  68. Option Explicit
  69. ' Hex objects stored in a quadtree.
  70. Private QtreeRoot As QtreeNode
  71. ' Global max and min world coordinates
  72. ' (including margins).
  73. Private DataXmin As Single
  74. Private DataXmax As Single
  75. Private DataYmin As Single
  76. Private DataYmax As Single
  77. ' Set the min and max allowed width and height.
  78. Private DataMinWid As Single
  79. Private DataMinHgt As Single
  80. Private DataMaxWid As Single
  81. Private DataMaxHgt As Single
  82. ' The aspect ratio of the viewport.
  83. Private VAspect As Single
  84. ' Current world window bounds.
  85. Private Wxmin As Single
  86. Private Wxmax As Single
  87. Private Wymin As Single
  88. Private Wymax As Single
  89. ' Prevent change events when we are adjusting the
  90. ' scroll bars.
  91. Private IgnoreSbarChange As Boolean
  92. ' Variables used for zooming.
  93. Private DrawingMode As Integer
  94. Const MODE_NONE = 0
  95. Const MODE_START_ZOOM = 1
  96. Const MODE_ZOOMING = 2
  97. Private StartX As Single
  98. Private StartY As Single
  99. Private LastX As Single
  100. Private LastY As Single
  101. Private OldMode As Integer
  102. ' The object that is highlighted.
  103. Private SelectedHex As Object
  104. ' Find the nearest hex.
  105. Private Function ObjectAt(ByVal X As Single, ByVal Y As Single) As Hex
  106.     Set ObjectAt = QtreeRoot.ObjectAt(X, Y)
  107. End Function
  108. ' End a zoom operation early. This happens if the
  109. ' user starts a zoom and the selects another menu
  110. ' item instead of doing the zoom.
  111. Private Sub StopZoom()
  112.     If DrawingMode <> MODE_START_ZOOM Then Exit Sub
  113.     DrawingMode = MODE_NONE
  114.     picCanvas.DrawMode = OldMode
  115.     picCanvas.MousePointer = vbDefault
  116. End Sub
  117. ' Change the level of magnification.
  118. Private Sub SetScaleFactor(fact As Single)
  119. Dim wid As Single
  120. Dim hgt As Single
  121. Dim mid As Single
  122.     fact = 1 / fact
  123.     ' Compute the new world window size.
  124.     wid = fact * (Wxmax - Wxmin)
  125.     hgt = fact * (Wymax - Wymin)
  126.     ' Center the new world window over the old.
  127.     mid = (Wxmax + Wxmin) / 2
  128.     Wxmin = mid - wid / 2
  129.     Wxmax = mid + wid / 2
  130.     mid = (Wymax + Wymin) / 2
  131.     Wymin = mid - hgt / 2
  132.     Wymax = mid + hgt / 2
  133.     ' Set the new world window bounds.
  134.     SetWorldWindow
  135. End Sub
  136. ' Adjust the world window so it is not too big,
  137. ' too small, off to one side, or of the wrong
  138. ' aspect ratio. Then map the world window to the
  139. ' viewport and force the viewport to repaint.
  140. Private Sub SetWorldWindow()
  141. Dim wid As Single
  142. Dim hgt As Single
  143. Dim xmid As Single
  144. Dim ymid As Single
  145. Dim aspect As Single
  146.     wid = Wxmax - Wxmin
  147.     xmid = (Wxmax + Wxmin) / 2
  148.     hgt = Wymax - Wymin
  149.     ymid = (Wymax + Wymin) / 2
  150.         
  151.     ' Make sure we're not too big or too small.
  152.     If wid > DataMaxWid Then
  153.         wid = DataMaxWid
  154.     ElseIf wid < DataMinWid Then
  155.         wid = DataMinWid
  156.     End If
  157.     If hgt > DataMaxHgt Then
  158.         hgt = DataMaxHgt
  159.     ElseIf hgt < DataMinHgt Then
  160.         hgt = DataMinHgt
  161.     End If
  162.     ' Make the aspect ratio match the
  163.     ' viewport aspect ratio.
  164.     aspect = hgt / wid
  165.     If aspect > VAspect Then
  166.         ' Too tall and thin. Make it wider.
  167.         wid = hgt / VAspect
  168.     Else
  169.         ' Too short and wide. Make it taller.
  170.         hgt = wid * VAspect
  171.     End If
  172.     ' Compute the new coordinates
  173.     Wxmin = xmid - wid / 2
  174.     Wxmax = xmid + wid / 2
  175.     Wymin = ymid - hgt / 2
  176.     Wymax = ymid + hgt / 2
  177.     ' Check that we're not off to one side.
  178.     If wid > DataMaxWid Then
  179.         ' We're wider than the picture. Center.
  180.         xmid = (DataXmax + DataXmin) / 2
  181.         Wxmin = xmid - wid / 2
  182.         Wxmax = xmid + wid / 2
  183.     Else
  184.         ' Else see if we're too far to one side.
  185.         If Wxmin < DataXmin And Wxmax < DataXmax Then
  186.             ' Adjust to the right.
  187.             Wxmax = Wxmax + DataXmin - Wxmin
  188.             Wxmin = DataXmin
  189.         End If
  190.         If Wxmax > DataXmax And Wxmin > DataXmin Then
  191.             ' Adjust to the left.
  192.             Wxmin = Wxmin + DataXmax - Wxmax
  193.             Wxmax = DataXmax
  194.         End If
  195.     End If
  196.     If hgt > DataMaxHgt Then
  197.         ' We're taller than the picture. Center.
  198.         ymid = (DataYmax + DataYmin) / 2
  199.         Wymin = ymid - hgt / 2
  200.         Wymax = ymid + hgt / 2
  201.     Else
  202.         ' See if we're too far to top or bottom.
  203.         If Wymin < DataYmin And Wymax < DataYmax Then
  204.             ' Adjust downward.
  205.             Wymax = Wymax + DataYmin - Wymin
  206.             Wymin = DataYmin
  207.         End If
  208.         If Wymax > DataYmax And Wymin > DataYmin Then
  209.             ' Adjust upward.
  210.             Wymin = Wymin + DataYmax - Wymax
  211.             Wymax = DataYmax
  212.         End If
  213.     End If
  214.     ' Map the world window to the viewport.
  215.     picCanvas.Scale (Wxmin, Wymax)-(Wxmax, Wymin)
  216.     ' Force the viewport to repaint.
  217.     picCanvas.Refresh
  218.         
  219.     ' Reset the scroll bars.
  220.     IgnoreSbarChange = True
  221.     HScrollBar.Visible = (wid < DataXmax - DataXmin)
  222.     VScrollBar.Visible = (hgt < DataYmax - DataYmin)
  223.     ' The values of the scroll bars will be where
  224.     ' the top/left of the world window should be.
  225.     VScrollBar.Min = 100 * (DataYmax)
  226.     VScrollBar.Max = 100 * (DataYmin + hgt)
  227.     HScrollBar.Min = 100 * (DataXmin)
  228.     HScrollBar.Max = 100 * (DataXmax - wid)
  229.     ' SmallChange moves the world window 1/10
  230.     ' of its width/height. Large change moves it
  231.     ' 9/10 of its width/height.
  232.     VScrollBar.SmallChange = 100 * (hgt / 10)
  233.     VScrollBar.LargeChange = 100 * (9 * hgt / 10)
  234.     HScrollBar.SmallChange = 100 * (wid / 10)
  235.     HScrollBar.LargeChange = 100 * (9 * wid / 10)
  236.     ' Set the current scroll bar values.
  237.     VScrollBar.Value = 100 * Wymax
  238.     HScrollBar.Value = 100 * Wxmin
  239.     IgnoreSbarChange = False
  240. End Sub
  241. ' Return to the default magnification scale.
  242. Private Sub SetScaleFull()
  243.     ' Reset the world window coordinates.
  244.     Wxmin = DataXmin
  245.     Wxmax = DataXmax
  246.     Wymin = DataYmin
  247.     Wymax = DataYmax
  248.     ' Set the new world window bounds.
  249.     SetWorldWindow
  250. End Sub
  251. Private Sub Form_Load()
  252.     MakeHexes
  253. End Sub
  254. Private Sub Form_Resize()
  255. Dim X As Single
  256. Dim Y As Single
  257. Dim wid As Single
  258. Dim hgt As Single
  259.     ' Fit the viewport to the window.
  260.     X = picCanvas.Left
  261.     Y = picCanvas.Top
  262.     wid = ScaleWidth - 2 * X - VScrollBar.Width
  263.     hgt = ScaleHeight - 2 * Y - HScrollBar.Height
  264.     picCanvas.Move X, Y, wid, hgt
  265.     VAspect = hgt / wid
  266.     ' Place the scroll bars next to the viewport.
  267.     X = picCanvas.Left + picCanvas.Width + 10
  268.     Y = picCanvas.Top
  269.     wid = VScrollBar.Width
  270.     hgt = picCanvas.Height
  271.     VScrollBar.Move X, Y, wid, hgt
  272.     X = picCanvas.Left
  273.     Y = picCanvas.Top + picCanvas.Height + 10
  274.     wid = picCanvas.Width
  275.     hgt = HScrollBar.Height
  276.     HScrollBar.Move X, Y, wid, hgt
  277.     ' Start at full scale.
  278.     SetScaleFull
  279. End Sub
  280. ' Make the Hexes.
  281. Private Sub MakeHexes()
  282. Const NUM_ROWS = 50
  283. Const NUM_COLS = 50
  284. Dim new_hex As Hex
  285. Dim i As Integer
  286. Dim j As Integer
  287. Dim X As Single
  288. Dim Y As Single
  289. Dim wid As Single
  290. Dim hgt As Single
  291.     wid = 2 * NUM_COLS + 1
  292.     hgt = 2 * NUM_ROWS + 1
  293.     DataXmin = -0.1 * wid   ' 10 % margins.
  294.     DataYmin = -0.1 * hgt
  295.     DataXmax = 1.1 * wid
  296.     DataYmax = 1.1 * hgt
  297.     DataMinWid = 10
  298.     DataMinHgt = 10
  299.     DataMaxWid = DataXmax - DataXmin
  300.     DataMaxHgt = DataYmax - DataYmin
  301.     MousePointer = vbHourglass
  302.     DoEvents
  303.     Set QtreeRoot = New QtreeNode
  304.     QtreeRoot.xmin = DataXmin
  305.     QtreeRoot.xmax = DataXmax
  306.     QtreeRoot.ymin = DataYmin
  307.     QtreeRoot.ymax = DataYmax
  308.     Y = 0
  309.     For i = 1 To NUM_ROWS
  310.         X = 0
  311.         For j = 1 To NUM_COLS
  312.             Set new_hex = New Hex
  313.             new_hex.Cx = X
  314.             new_hex.Cy = Y
  315.             new_hex.Radius = 0.4
  316.             ' Add the hex to the quadtree.
  317.             QtreeRoot.Add new_hex
  318.             X = X + 2
  319.         Next j
  320.         Y = Y + 2
  321.     Next i
  322.     MousePointer = vbDefault
  323. End Sub
  324. ' Move the world window.
  325. Private Sub HScrollBar_Change()
  326.     If IgnoreSbarChange Then Exit Sub
  327.     HScrollBarChanged
  328. End Sub
  329. ' The vertical scroll bar has been moved. Adjust
  330. ' the world window.
  331. Private Sub VScrollBarChanged()
  332. Dim hgt As Single
  333.     hgt = Wymax - Wymin
  334.     Wymax = VScrollBar.Value / 100
  335.     Wymin = Wymax - hgt
  336.     ' Remap the world window.
  337.     IgnoreSbarChange = True
  338.     SetWorldWindow
  339.     IgnoreSbarChange = False
  340. End Sub
  341. ' The horizontal scroll bar has been moved. Adjust
  342. ' the world window.
  343. Private Sub HScrollBarChanged()
  344. Dim wid As Single
  345.     wid = Wxmax - Wxmin
  346.     Wxmin = HScrollBar.Value / 100
  347.     Wxmax = Wxmin + wid
  348.     ' Remap the world window.
  349.     IgnoreSbarChange = True
  350.     SetWorldWindow
  351.     IgnoreSbarChange = False
  352. End Sub
  353. Private Sub mnuFileExit_Click()
  354.     StopZoom    ' If we're zooming, stop it.
  355.     Unload Me
  356. End Sub
  357. ' Change the level of magnification.
  358. Private Sub mnuScaleMag_Click(Index As Integer)
  359.     StopZoom    ' If we're zooming, stop it.
  360.     If Index = 1 Then
  361.         ' Return to full scale.
  362.         SetScaleFull
  363.     ElseIf Index < 10 Then
  364.         ' Magnify by the indicated amount.
  365.         SetScaleFactor CSng(Index)
  366.     Else
  367.         ' Zoom out by 1/(Index \ 10).
  368.         SetScaleFactor 1 / (Index \ 10)
  369.     End If
  370. End Sub
  371. ' Allow the user to select an area to zoom in on.
  372. Private Sub mnuScaleZoom_Click()
  373.     ' Enable zooming.
  374.     picCanvas.MousePointer = vbCrosshair
  375.     DrawingMode = MODE_START_ZOOM
  376. End Sub
  377. ' If we are zooming, start the rubberband hex.
  378. Private Sub picCanvas_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
  379.     Select Case DrawingMode
  380.         Case MODE_START_ZOOM
  381.             ' Start a zooming rubberband hex.
  382.             DrawingMode = MODE_ZOOMING
  383.         
  384.             OldMode = picCanvas.DrawMode
  385.             picCanvas.DrawMode = vbInvert
  386.             
  387.             StartX = X
  388.             StartY = Y
  389.             LastX = X
  390.             LastY = Y
  391.             picCanvas.Line (StartX, StartY)-(LastX, LastY), , B
  392.         
  393.         Case MODE_NONE
  394.             ' Select a hex.
  395.             Dim oldcolor As Long
  396.             ' Unhighlight the previous hex.
  397.             If Not SelectedHex Is Nothing Then
  398.                 SelectedHex.Highlighted = False
  399.                 SelectedHex.Draw picCanvas
  400.                 SelectedHex.Drawn = False
  401.             End If
  402.             ' Find the selected hex.
  403.             Set SelectedHex = ObjectAt(X, Y)
  404.             ' Highlight the selected hex.
  405.             If Not SelectedHex Is Nothing Then
  406.                 SelectedHex.Highlighted = True
  407.                 SelectedHex.Draw picCanvas
  408.                 SelectedHex.Drawn = False
  409.             End If
  410.     End Select
  411. End Sub
  412. ' If we are zooming, continue the rubberband hex.
  413. Private Sub picCanvas_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
  414.     If DrawingMode <> MODE_ZOOMING Then Exit Sub
  415.     ' Erase the old hex.
  416.     picCanvas.Line (StartX, StartY)-(LastX, LastY), , B
  417.     ' Draw the new hex.
  418.     LastX = X
  419.     LastY = Y
  420.     picCanvas.Line (StartX, StartY)-(LastX, LastY), , B
  421. End Sub
  422. ' If we are zooming, finish the rubberband hex.
  423. Private Sub picCanvas_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
  424. Dim wid As Single
  425. Dim hgt As Single
  426. Dim mid As Single
  427.     If DrawingMode <> MODE_ZOOMING Then Exit Sub
  428.     DrawingMode = MODE_NONE
  429.     ' Erase the old hex.
  430.     picCanvas.Line (StartX, StartY)-(LastX, LastY), , B
  431.     LastX = X
  432.     LastY = Y
  433.     ' We're done drawing for this rubberband hex.
  434.     picCanvas.DrawMode = OldMode
  435.     picCanvas.MousePointer = vbDefault
  436.     ' Set the new world window bounds.
  437.     If StartX > LastX Then
  438.         Wxmin = LastX
  439.         Wxmax = StartX
  440.     Else
  441.         Wxmin = StartX
  442.         Wxmax = LastX
  443.     End If
  444.     If StartY > LastY Then
  445.         Wymin = LastY
  446.         Wymax = StartY
  447.     Else
  448.         Wymin = StartY
  449.         Wymax = LastY
  450.     End If
  451.     ' Set the new world window bounds.
  452.     SetWorldWindow
  453. End Sub
  454. Private Sub picCanvas_Paint()
  455.     MousePointer = vbHourglass
  456.     DoEvents
  457.     ' Draw the nodes in the visible area.
  458.     QtreeRoot.Draw picCanvas, Wxmin, Wymin, Wxmax, Wymax
  459.     ' Mark all nodes as not drawn.
  460.     QtreeRoot.SetDrawn False
  461.     MousePointer = vbDefault
  462. End Sub
  463. ' Move the world window.
  464. Private Sub VScrollBar_Change()
  465.     If IgnoreSbarChange Then Exit Sub
  466.     VScrollBarChanged
  467. End Sub
  468.